package com.jmb.api.web.core.http;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.jmb.api.common.exception.ValidUtilException;
import com.jmb.api.common.exception.WebApiException;
import com.jmb.api.common.result.ResultCodeEnum;
import com.jmb.api.common.utils.InterfaceConstants;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.http.*;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.io.Serializable;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

// ResponseEntity HTTP 响应，包含响应体、状态码和响应头等完整信息

/**
 * HTTP请求工具类
 * 提供统一的HTTP客户端功能，包括GET、POST、PUT、DELETE、PATCH等请求方式
 * 支持URL路径变量解析、请求头设置、参数处理等功能
 */
@Slf4j
@Component
public class Request implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    private static Request restUtil;
    private static final HttpHeaders DEFAULT_HEADERS = getHeaders();


    // 实现 ApplicationContextAware 接口
    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        applicationContext = context;

    }

    // 提供静态方法获取 RequestFactory Bean
    private static RequestFactory getRequestFactory() {
        return applicationContext.getBean(RequestFactory.class);
    }

    private static class SingleRestTemplate {
        private static final RestTemplate INSTANCE = new RestTemplate();
    }

    public static RestTemplate getInstance() {
        RestTemplate restTemplate = SingleRestTemplate.INSTANCE;
        // 使用 ApplicationContext 获取的 RequestFactory
        restTemplate.setRequestFactory(getRequestFactory().byURLConnection());
        restTemplate.setErrorHandler(errorHandle());
        return restTemplate;
    }

    @PostConstruct
    public void init() {
        restUtil = this;
    }

    /**
     * 错误处理
     */
    public static ResponseErrorHandler errorHandle() {
        return new ResponseErrorHandler() {
            @Override
            public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
                return clientHttpResponse.getStatusCode().isError();
            }

            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
                log.error("Request 类 请求错误：{}", response.getStatusCode());

            }
        };
    }

    //get 请求

    /**
     * 发起GET请求
     *
     * @param url     请求地址
     * @param headers 请求头
     * @param params  请求参数
     * @return 响应实体
     */
    public static ResponseEntity get(String url, HashMap<String, String> headers, HashMap<String, String> params) {
        RestTemplate restTemplate = Request.getInstance();
        HttpHeaders httpHeaders = copyDefaultHeader();
        if (StringUtils.hasText(url)) {
            throw new WebApiException(ResultCodeEnum.web_Interface_url_not_null_ERROR);
        }
        if (httpHeaders != null) {
            httpHeaders.setAll(headers);
        }
        if (params == null) {
            return restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(httpHeaders), String.class);
        } else {
            HashMap<String, Object> urlParamsWrapper = pathVariableParser(url, new HashMap<>(params));
            url = (String) urlParamsWrapper.get("url");
            params = (HashMap<String, String>) urlParamsWrapper.get("params");
            return restTemplate.exchange(UriComponentsBuilder.fromHttpUrl(url).queryParams(hashMap2LinkedMultiValueMap(params))
                    .toUriString(), HttpMethod.GET, new HttpEntity<>(httpHeaders), String.class);
        }
    }

    /**
     * 发起POST请求
     *
     * @param url     请求地址
     * @param headers 请求头
     * @param params  请求参数
     * @param data    表单数据
     * @param json    JSON数据
     * @return 响应实体
     */
    public static ResponseEntity post(String url, HashMap<String, String> headers, HashMap<String, String> params,
                                      HashMap<String, String> data, String json) {
        return notGetRequest(HttpMethod.POST, url, headers, params, data, json);
    }

    /**
     * 发起PUT请求
     *
     * @param url     请求地址
     * @param headers 请求头
     * @param params  请求参数
     * @param data    表单数据
     * @param json    JSON数据
     * @return 响应实体
     */
    public static ResponseEntity put(String url, HashMap<String, String> headers, HashMap<String, String> params,
                                     HashMap<String, String> data, String json) {
        return notGetRequest(HttpMethod.PUT, url, headers, params, data, json);
    }

    /**
     * 发起PATCH请求
     *
     * @param url     请求地址
     * @param headers 请求头
     * @param params  请求参数
     * @param data    表单数据
     * @param json    JSON数据
     * @return 响应实体
     */
    public static ResponseEntity patch(String url, HashMap<String, String> headers, HashMap<String, String> params,
                                       HashMap<String, String> data, String json) {
        return notGetRequest(HttpMethod.PATCH, url, headers, params, data, json);
    }

    /**
     * 发起DELETE请求
     *
     * @param url     请求地址
     * @param headers 请求头
     * @param params  请求参数
     * @param data    表单数据
     * @param json    JSON数据
     * @return 响应实体
     */
    public static ResponseEntity delete(String url, HashMap<String, String> headers, HashMap<String, String> params,
                                        HashMap<String, String> data, String json) {
        return notGetRequest(HttpMethod.DELETE, url, headers, params, data, json);
    }

    /**
     * 处理非GET类型的HTTP请求
     *
     * @param httpMethod 请求方式（post/put/delete）
     * @param url        请求地址
     * @param headers    请求头
     * @param params     请求参数
     * @param data       表单数据
     * @param json       JSON数据
     * @return 响应实体
     */
    private static ResponseEntity notGetRequest(HttpMethod httpMethod, String url, HashMap<String, String> headers,
                                                HashMap<String, String> params, HashMap<String, String> data, String json) {

        RestTemplate restTemplate = Request.getInstance();
        HttpHeaders httpHeaders = copyDefaultHeader();

        if (headers != null) {
            httpHeaders.setAll(headers);
        }
        // 检查参数有效性：data和json不能同时存在
        if (StringUtils.hasText(json) && data != null) {
            log.error("请求参数错误：data和json参数不能同时存在");
            throw new WebApiException(ResultCodeEnum.PARAM_ERROR);
        }

        // 解析URL中的路径变量
        HashMap<String, Object> urlParamsWrapper = pathVariableParser(url, params == null ? null : new HashMap<>(params));
        url = (String) urlParamsWrapper.get("url");
        params = (HashMap<String, String>) urlParamsWrapper.get("params");

        // 处理查询参数
        if (params != null && !params.isEmpty()) {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParams(hashMap2LinkedMultiValueMap(params));
            url = builder.toUriString();
        }
        // 根据参数类型设置不同的Content-Type并发送请求
        if (data != null) {
            LinkedMultiValueMap<String, String> formData = hashMap2LinkedMultiValueMap(data);
            httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            return restTemplate.exchange(url, httpMethod, new HttpEntity<>(formData, httpHeaders), String.class);
        } else {
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            return restTemplate.exchange(url, httpMethod, new HttpEntity<>(json, httpHeaders), String.class);
        }
    }

    /**
     * @param httpMethod 请求方式
     * @param url 请求地址
     * @param headers 请求头
     * @param params 请求参数
     * @param body 请求body
     * @param mediaType 请求body类型
     * @return 响应实体
     */
    public static ResponseEntity requestPro(HttpMethod httpMethod, String url, HashMap<String, String> headers,
                                            HashMap<String, String> params, String body, MediaType mediaType)
            {

        RestTemplate restTemplate = Request.getInstance();
        HttpHeaders httpHeaders = copyDefaultHeader();

        if (StringUtils.isEmpty(url)) {
            throw new ValidUtilException("url error");
        }

        HashMap<String, Object> urlParamsWrapper = pathVariableParser(url, params);
        url = (String) urlParamsWrapper.get("url");
        params = (HashMap<String, String>) urlParamsWrapper.get("params");

        if (params != null && !params.isEmpty()) {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParams(hashMap2LinkedMultiValueMap(params));
            url = builder.toUriString();
        }
        httpHeaders.setContentType(mediaType);
        if (headers != null) {
            httpHeaders.setAll(headers);
        }
        if (body != null && !body.isEmpty()) {
            return restTemplate.exchange(url, httpMethod, new HttpEntity(body, httpHeaders), String.class);
        } else {
            return restTemplate.exchange(url, httpMethod, new HttpEntity(httpHeaders), String.class);
        }
    }

    /**
     * 通用HTTP请求方法，支持自定义请求体和媒体类型
     *
     * @param httpMethod 请求方式
     * @param url        请求地址
     * @param headers    请求头
     * @param params     请求参数
     * @param body       请求体
     * @param mediaType  请求体类型
     * @return 响应实体
     */
    public static ResponseEntity requestPro(HttpMethod httpMethod, String url, HashMap<String, String> headers,
                                            HashMap<String, String> params, HashMap<String, String> body, MediaType mediaType) {

        RestTemplate restTemplate = Request.getInstance();
        HttpHeaders httpHeaders = copyDefaultHeader();

        // 解析URL中的路径变量
        HashMap<String, Object> urlParamsWrapper = pathVariableParser(url, params == null ? null : new HashMap<>(params));
        url = (String) urlParamsWrapper.get("url");
        params = (HashMap<String, String>) urlParamsWrapper.get("params");

        // 处理查询参数
        if (params != null && !params.isEmpty()) {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParams(hashMap2LinkedMultiValueMap(params));
            url = builder.toUriString();
        }
        httpHeaders.setContentType(mediaType);
        if (headers != null) {
            httpHeaders.setAll(headers);
        }
        // 根据body参数决定发送表单数据还是空请求体
        if (body != null && !body.isEmpty()) {
            LinkedMultiValueMap<String, String> form = hashMap2LinkedMultiValueMap(body);
            return restTemplate.exchange(url, httpMethod, new HttpEntity<>(form, httpHeaders), String.class);
        } else {
            return restTemplate.exchange(url, httpMethod, new HttpEntity<>(httpHeaders), String.class);
        }
    }

    /**
     * 通用HTTP请求方法，支持自定义媒体类型
     *
     * @param httpMethod 请求方式
     * @param url        请求地址
     * @param headers    请求头
     * @param params     请求参数
     * @param mediaType  请求体类型
     * @return 响应实体
     */
    public static ResponseEntity requestPro(HttpMethod httpMethod, String url, HashMap<String, String> headers,
                                            HashMap<String, String> params, MediaType mediaType) {

        RestTemplate restTemplate = Request.getInstance();
        HttpHeaders httpHeaders = copyDefaultHeader();

        // 处理查询参数
        if (params != null && !params.isEmpty()) {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
                    .queryParams(hashMap2LinkedMultiValueMap(params));
            url = builder.toUriString();
        }
        httpHeaders.setContentType(mediaType);
        if (headers != null) {
            httpHeaders.setAll(headers);
        }
        return restTemplate.exchange(url, httpMethod, new HttpEntity<>(httpHeaders), String.class);
    }


    /**
     * 解析URL中的路径变量并替换为实际值
     *
     * @param url    包含路径变量的URL，如 http://example.com/users/{userId}
     * @param params 包含变量值的参数映射
     * @return 包含解析后URL和剩余参数的映射
     */
    public static HashMap<String, Object> pathVariableParser(String url, HashMap<String, String> params) {
        // 匹配url中的参数
        Pattern compile = Pattern.compile(InterfaceConstants.URL_REGEX);
        // 创建匹配器
        Matcher matcher = compile.matcher(url);
        HashMap<String, Object> result = new HashMap<>();
        HashMap<String, String> parmsCopy = params == null ? new HashMap<>() : new HashMap<>(params);
        while (matcher.find()) {
            String pathVariable = matcher.group();
            String key = pathVariable.substring(1, pathVariable.length() - 1);
            // 检查参数是否为空或不包含所需键
            if (parmsCopy.isEmpty()) {
                throw new WebApiException(ResultCodeEnum.web_Interface_url_ERROR);
            }
            if (parmsCopy.containsKey(key)) {
                throw new WebApiException(ResultCodeEnum.web_Interface_url_ERROR);
            } else {
                url = url.replace(pathVariable, parmsCopy.remove(key));
            }

        }
        result.put("url", url);
        result.put("params", parmsCopy);
        return result;

    }

    /**
     * 将HashMap转换为LinkedMultiValueMap
     * LinkedMultiValueMap支持一个键对应多个值
     *
     * @param hashMap 源HashMap
     * @return 转换后的LinkedMultiValueMap
     */
    private static <K, V> LinkedMultiValueMap<K, V> hashMap2LinkedMultiValueMap(HashMap<K, V> hashMap) {
        LinkedMultiValueMap<K, V> result = new LinkedMultiValueMap<>();
        if (hashMap == null || hashMap.isEmpty()) {
            return result;
        }
        for (Map.Entry<K, V> entry : hashMap.entrySet()) {
            result.add(entry.getKey(), entry.getValue());
        }
        return result;
    }

    /**
     * 获取HTTP响应状态码
     *
     * @param response 响应实体
     * @return 状态码数值
     */
    public static Integer code(ResponseEntity response) {
        return response.getStatusCode().value();
    }
    // 获取Http响应正文body

    /**
     * 获取HTTP响应正文内容
     *
     * @param response 响应实体
     * @return 响应体字符串类型
     */
    public static String body(ResponseEntity response) {
        if (response.getBody() != null) {
            return response.getBody().toString();
        } else {
            return "";
        }
    }

    // 获取http响应头

    /**
     * 获取HTTP响应头信息
     *
     * @param response 响应实体
     * @return 响应头字符串类型
     */
    public static String headers(ResponseEntity response) {
        return JSON.toJSONString(response.getHeaders());
    }

    /**
     * 获取格式化的HTTP响应头信息
     *
     * @param response 响应实体
     * @return 格式化后的响应头JSON字符串
     */
    public static String headersPretty(ResponseEntity response) {
        return JSON.toJSONString(response.getHeaders(), JSONWriter.Feature.PrettyFormat);
    }

    /**
     * 获取HTTP响应头并转换为JSONObject
     *
     * @param response 响应实体
     * @return 响应头的JSONObject表示
     */
    public static JSONObject header(ResponseEntity response) {

        return JSONObject.parseObject(JSON.toJSONString(response.getHeaders()));
    }

    private static HttpHeaders getHeaders() {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.put("User-Agent", Arrays.asList(InterfaceConstants.DEFAULT_USER_AGENT));
        httpHeaders.put("Accept", Arrays.asList(InterfaceConstants.DEFAULT_ACCEPT));
        httpHeaders.put("Accept-Encoding", Arrays.asList(InterfaceConstants.DEFAULT_ACCEPT_ENCODING));
        httpHeaders.put("Accept-Language", Arrays.asList(InterfaceConstants.DEFAULT_ACCEPT_LANGUAGE));
        return httpHeaders;
    }

    private static HttpHeaders copyDefaultHeader() {
        return new HttpHeaders(DEFAULT_HEADERS);
    }
}